package com.chen.base.utils;

import cn.hutool.core.util.ReflectUtil;
import com.chen.base.inter.ConvertTo;
import com.chen.root.annotation.TreeParentField;
import com.chen.root.oclass.TreeNode;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.function.Predicate;
import java.util.stream.Collectors;

/**
 * @Author: 陈锦龙
 * @Date: 2025/10/9 10:18
 */
public class TreeUtil {

    /**
     * 构建树结构的数据集
     * @param sources 源数据集
     * @param rootJudge 判断第一层根目录的标准
     * @param convertTo 将源数据转换为树节点对象
     * @return 树结构的数据集
     * @param <T> 源数据类型
     */
    public static <T> List<TreeNode> buildTree(List<T> sources, Predicate<T> rootJudge, ConvertTo<T> convertTo) {
        List<TreeNode> treeList = new CopyOnWriteArrayList<>();
        List<CompletableFuture<Void>> futureList = new ArrayList<>();

        List<T> rootNodes = sources.stream().filter(rootJudge).collect(Collectors.toList());
        List<T> notRootNodes = sources.stream().filter(t -> !rootJudge.test(t)).collect(Collectors.toList());

        for (T rootNode : rootNodes) {
            futureList.add(AsyncUtil.runAsync(() -> {
                treeList.add(getTreeNode(rootNode, notRootNodes, convertTo, 1));
            }));
        }

        if (futureList.size() > 0){
            AsyncUtil.allOf(futureList.toArray(new CompletableFuture<?>[0]));
        }
        return StreamUtil.sort(treeList, TreeNode::getSerialNum, true);
    }

    public static <T> TreeNode getTreeNode(T parent, List<T> notRootNodes, ConvertTo<T> convertTo, int level) {
        TreeNode parentNode = convertTo.apply(parent, level);

        List<TreeNode> childrenList = new ArrayList<>();
        for (T node : notRootNodes) {
            for (Field field : ReflectUtil.getFields(node.getClass())) {
                TreeParentField parentField = field.getAnnotation(TreeParentField.class);
                if (parentField != null){
                    Object parentValue = ReflectUtil.getFieldValue(node, field);
                    if (parentNode.getId().equals(parentValue)){
                        TreeNode children = getTreeNode(node, notRootNodes, convertTo, level + 1);
                        childrenList.add(children);
                    }
                    break;
                }
            }
        }

        if (parentNode.getSerialNum() == null){
            parentNode.setSerialNum(-childrenList.size());
        }

        parentNode.setChildren(StreamUtil.sort(childrenList, TreeNode::getSerialNum, true));
        return parentNode;
    }
}
